import { Canvas, useFrame } from "@react-three/fiber";
import { OrbitControls, useGLTF, Center, useAnimations } from "@react-three/drei";
import { useEffect, useMemo, useRef, useState, useCallback } from "react";
import { useDispatch, useSelector } from 'react-redux';
import type { RootState } from '../store/store';
import { setLanguage, toggleTheme } from '../store/counterSlice';
import AuthButton from '../components/AuthButton';
import i18n from '../i18/i18n';
import { useTranslation } from 'react-i18next';
import { LoopRepeat, Group, AnimationMixer, Object3D, Vector3, Mesh, MeshStandardMaterial } from "three";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js";
import { danmuStorageService } from '../services/danmuStorage';
import DanmuManager from '../components/DanmuManager';
import EmojiPicker from '../components/EmojiPicker';
import DanmuSettingsPanel from '../components/DanmuSettings';
import SensitiveWordsManager from '../components/SensitiveWordsManager';
import VoiceSettingsPanel from '../components/VoiceSettings';
import ChatExport from '../components/ChatExport';
import SkinChangeModal from '../components/SkinChangeModal';
import { sensitiveWordsService } from '../services/sensitiveWordsService';
import type { DanmuSettings as DanmuSettingsInterface } from '../types/danmuSettings';
import { DEFAULT_DANMU_SETTINGS } from '../types/danmuSettings';
import './mySelf.css'
import { useNavigate } from 'react-router-dom'
import { useVoiceRecording } from '../hooks/useVoiceRecording'
import { authService } from '../services/auth'
import { useDanmuOcclusion } from '../hooks/useDanmuOcclusion'
import { DanmuElement } from '../components/DanmuElement'
import { useCharacterPositionUpdater } from '../hooks/useCharacterPositionUpdater'
import { AiResponseBubble, ConversationStatus } from '../components/StreamingText'
import { voiceChatManager, type VoiceChatState } from '../services/voiceChatManager'

function MySelf() {
  const dispatch = useDispatch();
  const navigate = useNavigate();
  const language = useSelector((state: RootState) => state.counter.language) as 'en' | 'zh';
  const theme = useSelector((state: RootState) => state.counter.theme) as 'light' | 'dark';
  // 角色信息由 AuthButton 控制权限，这里无需直接使用

  // 挂载与 theme 改变时同步 html 的 dark 类
  useEffect(() => {
    const root = document.documentElement
    if (theme === 'dark') {
      root.classList.add('dark')
    } else {
      root.classList.remove('dark')
    }
  }, [theme])
  const { t } = useTranslation();
  const modelAreaRef = useRef<HTMLDivElement>(null);
  const [isModelReady, setIsModelReady] = useState(false);
  const url = "https://models.readyplayer.me/68d5ec283f253007467a4b34.glb";
  console.log('模型URL:', url);
  const [currentAnimation, setCurrentAnimation] = useState("idle");

  // 换肤相关状态 - 分离衣服、裤子、鞋子和头发
  const [currentClothingSkin, setCurrentClothingSkin] = useState('original'); // 衣服皮肤
  const [currentPantsSkin, setCurrentPantsSkin] = useState('original'); // 裤子皮肤
  const [currentShoesSkin, setCurrentShoesSkin] = useState('original'); // 鞋子皮肤
  const [currentHairSkin, setCurrentHairSkin] = useState('original'); // 头发皮肤
  const [availableSkins] = useState([
    { id: 'original', name: '原始颜色', color: 'original' },
    { id: 'red', name: '红色', color: '#FF6B6B' },
    { id: 'blue', name: '蓝色', color: '#4ECDC4' },
    { id: 'green', name: '绿色', color: '#45B7D1' },
    { id: 'purple', name: '紫色', color: '#9B59B6' },
    { id: 'yellow', name: '黄色', color: '#F39C12' }
  ]);

  const [danmuText, setDanmuText] = useState("");
  // 实时弹幕状态
  const [danmus, setDanmus] = useState<Array<{ id: number; text: string; color: string; duration: number; top: number; paused?: boolean }>>([]);
  const danmuIdRef = useRef(0);
  const rowOccupancyRef = useRef<{ [key: number]: number }>({});

  const videoRef = useRef<HTMLVideoElement>(null);
  const triggeredStoredDanmus = useRef<Set<string>>(new Set()); // 记录已触发的存储弹幕
  const [isVideoPaused, setIsVideoPaused] = useState(false);
  // 弹幕管理器显示状态
  const [showDanmuManager, setShowDanmuManager] = useState(false);
  // 表情选择器显示状态
  const [showEmojiPicker, setShowEmojiPicker] = useState(false);
  // 弹幕设置状态
  const [danmuSettings, setDanmuSettings] = useState<DanmuSettingsInterface>(DEFAULT_DANMU_SETTINGS);
  // 弹幕设置面板显示状态
  const [showDanmuSettings, setShowDanmuSettings] = useState(false);
  // AI对话状态
  const [voiceChatState, setVoiceChatState] = useState<VoiceChatState>({
    isListening: false,
    isProcessing: false,
    isAiThinking: false,
    isAiResponding: false,
    isSpeaking: false,
    userMessage: '',
    aiResponse: '',
    error: null
  });
  // 敏感词管理面板显示状态
  const [showSensitiveWordsManager, setShowSensitiveWordsManager] = useState(false);
  // 语音设置面板显示状态
  const [showVoiceSettings, setShowVoiceSettings] = useState(false);
  // 对话导出面板显示状态
  const [showChatExport, setShowChatExport] = useState(false);
  // 换肤弹框显示状态
  const [showSkinChangeModal, setShowSkinChangeModal] = useState(false);

  // 弹幕遮挡检测
  const { danmusWithOcclusion, registerDanmuElement } = useDanmuOcclusion(
    danmus,
    {
      enabled: danmuSettings.enabled,
      debugMode: false,
      checkInterval: 100,
      occlusionThreshold: 0.3,
      characterBounds: {
        width: 0.3,
        height: 0.6,
        offsetY: 0.1,
      },
    }
  );

  // 语音录制功能
  const {
    isRecording,
    isProcessing,
    error: voiceError,
    result: voiceResult,
    startRecording,
    stopRecording,
    clearResult
  } = useVoiceRecording();

  // 语音识别结果状态 - 显示在彩球旁边
  const [voiceDisplayText, setVoiceDisplayText] = useState<string>('');
  const [voiceDisplayTimeout, setVoiceDisplayTimeout] = useState<number | null>(null);
  const [lastProcessedVoiceResult, setLastProcessedVoiceResult] = useState<string>('');

  // 初始化语音对话管理器
  useEffect(() => {
    voiceChatManager.setCallbacks({
      onStateChange: (state) => {
        console.log('🔄 状态变化:', state);
        setVoiceChatState(state);
      },
      onUserMessage: (message) => {
        console.log('👤 用户消息:', message);
      },
      onAiResponse: (response, isComplete) => {
        console.log('🤖 AI回复:', response, '完成:', isComplete);
      },
      onError: (error) => {
        console.error('❌ AI对话错误:', error);
      }
    });

    console.log('🔧 AI语音对话功能已初始化，等待用户操作...');
  }, []);

  // 当语音识别成功时，显示在彩球旁边，并触发本地免费回复
  useEffect(() => {
    console.log('🔍 语音识别状态变化:', { voiceResult, isRecording, isProcessing, voiceError });

    if (voiceResult && voiceResult !== lastProcessedVoiceResult) {
      console.log('✅ 收到语音识别结果:', voiceResult);

      // 清除之前的定时器
      if (voiceDisplayTimeout) {
        clearTimeout(voiceDisplayTimeout);
      }

      // 设置显示文本
      setVoiceDisplayText(voiceResult);
      setLastProcessedVoiceResult(voiceResult);

      // 启动AI对话
      voiceChatManager.handleVoiceResult(voiceResult);

      // 设置5秒后自动清除
      const timeout = setTimeout(() => {
        setVoiceDisplayText('');
        clearResult();
        setLastProcessedVoiceResult('');
      }, 5000);

      setVoiceDisplayTimeout(timeout);
    }
  }, [voiceResult, clearResult, voiceDisplayTimeout, isRecording, isProcessing, voiceError, lastProcessedVoiceResult]);

  // 组件卸载时清除定时器
  useEffect(() => {
    return () => {
      if (voiceDisplayTimeout) {
        clearTimeout(voiceDisplayTimeout);
      }
    };
  }, [voiceDisplayTimeout]);

  // 确保模型容器完全渲染后再初始化3D场景
  useEffect(() => {
    // 延迟初始化，确保DOM完全渲染
    const timer = setTimeout(() => {
      setIsModelReady(true);
    }, 200);

    return () => {
      clearTimeout(timer);
    };
  }, []);

  // 监听窗口大小变化，确保模型位置稳定
  useEffect(() => {
    let resizeTimeout: number;

    const handleResize = () => {
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(() => {
        // 窗口大小变化时的处理逻辑已移至Avatar组件内部
        console.log('窗口大小变化，模型位置由Avatar组件内部处理');
      }, 100);
    };

    window.addEventListener('resize', handleResize);
    return () => {
      window.removeEventListener('resize', handleResize);
      clearTimeout(resizeTimeout);
    };
  }, []);

  // 处理表情选择
  const handleEmojiSelect = (emoji: string) => {
    setDanmuText(prev => prev + emoji);
    setShowEmojiPicker(false);
  };

  // 处理衣服换肤
  const handleClothingSkinChange = (skinId: string) => {
    setCurrentClothingSkin(skinId);
    console.log('切换到衣服皮肤:', skinId);
  };

  // 处理裤子换肤
  const handlePantsSkinChange = (skinId: string) => {
    setCurrentPantsSkin(skinId);
    console.log('切换到裤子皮肤:', skinId);
  };

  // 处理鞋子换肤
  const handleShoesSkinChange = (skinId: string) => {
    setCurrentShoesSkin(skinId);
    console.log('切换到鞋子皮肤:', skinId);
  };

  // 处理头发换肤
  const handleHairSkinChange = (skinId: string) => {
    setCurrentHairSkin(skinId);
    console.log('切换到头发皮肤:', skinId);
  };

  // 处理换肤弹框
  const handleOpenSkinModal = () => {
    setShowSkinChangeModal(true);
  };

  const handleCloseSkinModal = () => {
    setShowSkinChangeModal(false);
  };

  const handleApplyClothingSkin = (skinId: string) => {
    setCurrentClothingSkin(skinId);
    console.log('确认应用衣服皮肤:', skinId);
  };

  const handleApplyPantsSkin = (skinId: string) => {
    setCurrentPantsSkin(skinId);
    console.log('确认应用裤子皮肤:', skinId);
  };

  const handleApplyShoesSkin = (skinId: string) => {
    setCurrentShoesSkin(skinId);
    console.log('确认应用鞋子皮肤:', skinId);
  };

  const handleApplyHairSkin = (skinId: string) => {
    setCurrentHairSkin(skinId);
    console.log('确认应用头发皮肤:', skinId);
  };

  // 处理弹幕设置变化
  const handleDanmuSettingsChange = (newSettings: DanmuSettingsInterface) => {
    setDanmuSettings(newSettings);
    // 保存到本地存储
    localStorage.setItem('danmuSettings', JSON.stringify(newSettings));
  };

  // 从本地存储加载弹幕设置
  useEffect(() => {
    const savedSettings = localStorage.getItem('danmuSettings');
    if (savedSettings) {
      try {
        const parsed = JSON.parse(savedSettings);
        setDanmuSettings(parsed);
      } catch (error) {
        console.error('Failed to parse danmu settings:', error);
      }
    }
  }, []);

  // 添加视频时间监听，触发预设弹幕和存储弹幕
  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    // 预设弹幕数据
    const presetDanmus = [
      { text: "我是小帅", time: 2 },
      { text: "主播主播", time: 5 },
      { text: "你会唱歌吗", time: 8 },
      { text: "666666", time: 12 },
      { text: "太棒了", time: 15 },
      { text: "学到了", time: 18 },
      { text: "前排围观", time: 22 },
      { text: "感谢分享", time: 25 }
    ];

    const handleTimeUpdate = () => {
      const currentTime = video.currentTime;

      // 如果视频暂停，不触发新弹幕
      if (video.paused) {
        return;
      }

      // 检查预设弹幕
      presetDanmus.forEach(preset => {
        if (Math.abs(currentTime - preset.time) < 0.5) {
          const existingDanmu = danmus.find(d => d.text === preset.text);
          if (!existingDanmu) {
            const id = ++danmuIdRef.current;
            const colors = [
              '#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7',
              '#a29bfe', '#fd79a8', '#00b894', '#e17055', '#74b9ff'
            ];
            const color = colors[Math.floor(Math.random() * colors.length)];
            const duration = 4 + Math.random() * 6;
            const top = Math.random() * 80 + 10;

            setDanmus(prev => [...prev, { id, text: preset.text, color, duration, top }]);

            setTimeout(() => {
              setDanmus(prev => prev.filter(x => x.id !== id));
            }, (duration + 1) * 1000);
          }
        }
      });

      // 检查存储的弹幕
      const storedDanmus = danmuStorageService.getDanmusAtTime(currentTime, 0.5);
      storedDanmus.forEach(storedDanmu => {
        if (!triggeredStoredDanmus.current.has(storedDanmu.id)) {
          triggeredStoredDanmus.current.add(storedDanmu.id);

          const id = ++danmuIdRef.current;
          const duration = 4 + Math.random() * 6;
          const top = Math.random() * 80 + 10;

          setDanmus(prev => [...prev, {
            id,
            text: storedDanmu.text,
            color: storedDanmu.color,
            duration,
            top
          }]);

          setTimeout(() => {
            setDanmus(prev => prev.filter(x => x.id !== id));
          }, (duration + 1) * 1000);
        }
      });
    };

    // 重置已触发弹幕记录
    const handlePlay = () => {
      triggeredStoredDanmus.current.clear();
      setIsVideoPaused(false);
    };

    // 处理视频暂停
    const handlePause = () => {
      setIsVideoPaused(true);
    };

    // 处理视频播放
    const handleVideoPlay = () => {
      setIsVideoPaused(false);
    };

    video.addEventListener('timeupdate', handleTimeUpdate);
    video.addEventListener('play', handlePlay);
    video.addEventListener('pause', handlePause);
    video.addEventListener('playing', handleVideoPlay);
    video.addEventListener('seeked', handlePlay); // 拖拽进度条时也重置

    return () => {
      video.removeEventListener('timeupdate', handleTimeUpdate);
      video.removeEventListener('play', handlePlay);
      video.removeEventListener('pause', handlePause);
      video.removeEventListener('playing', handleVideoPlay);
      video.removeEventListener('seeked', handlePlay);
    };
  }, [danmus]);

  // 可用的动画列表（使用 i18n 文案）
  const animationOptions = useMemo(() => ([
    { value: "idle", label: t('daiji'), type: "model" },
    { value: "greeting", label: t('greeting'), type: "fbx", file: "Standing Greeting.fbx" },
    { value: "clap", label: t('clap'), type: "fbx", file: "Standing Clap.fbx" },
    { value: "angry", label: t('angry'), type: "fbx", file: "Angry.fbx" },
    { value: "flair", label: t('flair'), type: "fbx", file: "Flair.fbx" },
    { value: "hiphop", label: t('hiphop'), type: "fbx", file: "Hip Hop Dancing.fbx" },
    { value: "rumba", label: t('rumba'), type: "fbx", file: "Rumba Dancing.fbx" },
  ]), [t]);

  console.log('MySelf组件渲染，当前动画:', currentAnimation);
  console.log('动画选项:', animationOptions);
  console.log('模型准备状态:', isModelReady);

  return (
    <div className="myself-container">
      {/* 天花板 */}
      <div className="myself-ceiling"></div>

      {/* 主内容区域 */}
      <div className="myself-content">
        <div className="myself-model-area" ref={modelAreaRef}>
          {/* 动作选择菜单 - 左上角 */}
          <div className="myself-animation-menu">
            <select
              value={currentAnimation}
              className="myself-animation-select"
              onChange={(e) => {
                setCurrentAnimation(e.target.value);
              }}
            >
              {animationOptions.map(option => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </div>

          {/* 模型区域 - 只有在容器准备好后才渲染 */}
          {isModelReady ? (
            <Canvas
              gl={{ alpha: true }}
              className="myself-canvas"
              camera={{ position: [-1, 1.5, 3], fov: 50 }}
              style={{
                width: '100%',
                height: '100%',
                position: 'absolute',
                top: 0,
                left: 0
              }}
            >
              <OrbitControls
                enableDamping
                target={[-1, 1.5, 0]}
                enablePan={false}
                enableZoom={false}
                enableRotate={false}
                autoRotate={false}
              />
              <ambientLight intensity={0.9} />
              <directionalLight position={[3, 5, 2]} intensity={1.2} />
              <directionalLight position={[-2, 2, -2]} intensity={0.4} />
              <Center position={[-1, 1.5, 0]}>
                <Avatar
                  url={url}
                  currentAnimation={currentAnimation}
                  currentClothingSkin={currentClothingSkin}
                  currentPantsSkin={currentPantsSkin}
                  currentShoesSkin={currentShoesSkin}
                  currentHairSkin={currentHairSkin}
                />
              </Center>
            </Canvas>
          ) : (
            <div className="myself-canvas-loading">
              <div style={{
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                height: '100%',
                fontSize: '16px',
                color: '#666'
              }}>
                加载数字人模型中...
              </div>
            </div>
          )}
        </div>

        {/* 右侧视频区域 */}
        <div className="myself-right-panel">
          {/* 右侧控制按钮（右上角） */}
          <div className="myself-right-controls">
            <span className="myself-inline-link" onClick={() => navigate('/look')} role="button">进入3D展览馆</span>
            <button
              className="myself-control-btn"
              onClick={handleOpenSkinModal}
              title="换肤设置"
            >
              🎨 换肤
            </button>
            {/* 语言切换按钮 - 只有管理员能用 */}
            <AuthButton className="myself-control-btn"
              allowRoles={['admin']} deny onClick={() => {
                const next = language === 'en' ? 'zh' : 'en'
                dispatch(setLanguage(next))
                i18n.changeLanguage(next)
              }}>
              {language === 'en' ? '中文' : 'English'}
            </AuthButton>
            {/* 主题切换按钮 - 只有管理员能用 */}
            <AuthButton className="myself-control-btn" allowRoles={['admin']} deny onClick={() => {
              dispatch(toggleTheme())
            }}>
              {theme === 'dark' ? '日间' : '夜间'}
            </AuthButton>
            <button
              className="myself-control-btn"
              onClick={() => {
                authService.logout()
                navigate('/login', { replace: true })
              }}
              style={{ marginLeft: 8 }}
            >
              退出登录
            </button>
          </div>

          <div className="myself-video-frame">
            {/* 提示框 */}
            <div className="myself-notification">
              呼唤"小帅小帅",开始给你吹牛逼
              <div className="myself-bell-icon"></div>
            </div>

            <div className="myself-video-box">
              <video ref={videoRef} className="myself-video" src="/video/bw.mp4" controls preload="metadata" />
              {/* 弹幕层：视频上方显示 */}
              {danmuSettings.enabled && (
                <div className="danmu-layer">
                  {danmusWithOcclusion.map(d => (
                    <DanmuElement
                      key={d.id}
                      id={d.id}
                      onRegister={registerDanmuElement}
                      className={`danmu-item ${isVideoPaused ? 'paused' : ''} ${d.occluded ? 'occluded' : ''}`}
                      style={{
                        color: d.color,
                        top: `${d.top}%`,
                        animationDuration: `${d.duration}s`,
                        animationPlayState: isVideoPaused ? 'paused' : 'running',
                        fontSize: `${danmuSettings.fontSize}px`,
                        opacity: danmuSettings.opacity,
                      }}
                    >
                      {d.text}
                    </DanmuElement>
                  ))}

                </div>
              )}
              <div className="danmu-bar">
                <input
                  className="danmu-input"
                  placeholder="请输入弹幕"
                  value={danmuText}
                  onChange={(e) => setDanmuText(e.target.value)}
                />
                <button
                  className="danmu-send"
                  onClick={() => {
                    const text = danmuText.trim();
                    if (!text || !videoRef.current) return;

                    const video = videoRef.current;

                    // 如果视频暂停，不允许发送弹幕
                    if (video.paused) {
                      alert('视频暂停时无法发送弹幕，请先播放视频');
                      return;
                    }

                    // 敏感词过滤
                    const filterResult = sensitiveWordsService.containsSensitiveWords(text);
                    if (filterResult.hasSensitive) {
                      if (filterResult.filteredText === '') {
                        // 完全屏蔽
                        alert(`弹幕包含敏感词"${filterResult.matchedWords.join('、')}"，已被屏蔽`);
                        setDanmuText("");
                        return;
                      } else {
                        // 替换模式
                        const confirmReplace = window.confirm(
                          `弹幕包含敏感词"${filterResult.matchedWords.join('、')}"，是否替换为"${filterResult.filteredText}"？`
                        );
                        if (!confirmReplace) {
                          setDanmuText("");
                          return;
                        }
                        // 使用过滤后的文本
                        setDanmuText(filterResult.filteredText);
                        return; // 重新触发发送逻辑
                      }
                    }

                    const currentTime = video.currentTime;

                    const id = ++danmuIdRef.current;

                    // 生成更丰富的随机颜色
                    const colors = [
                      '#ff6b6b', '#4ecdc4', '#45b7d1', '#f9ca24', '#6c5ce7',
                      '#a29bfe', '#fd79a8', '#00b894', '#e17055', '#74b9ff',
                      '#0984e3', '#00cec9', '#55a3ff', '#fd79a8', '#fdcb6e'
                    ];
                    const color = colors[Math.floor(Math.random() * colors.length)];

                    // 延迟保存弹幕到存储，避免立即触发存储弹幕逻辑
                    setTimeout(() => {
                      danmuStorageService.saveDanmu({
                        text,
                        timestamp: currentTime,
                        color
                      });
                    }, 1000); // 延迟1秒保存

                    // 根据设置计算移动速度 (速度值越大，duration越小，移动越快)
                    const baseDuration = 12 - danmuSettings.speed; // 1-10 映射到 11-2秒
                    const duration = baseDuration + Math.random() * 2; // 添加随机性

                    // 智能行分配，避免重叠
                    const maxRows = danmuSettings.maxRows;
                    const now = Date.now();

                    // 清理过期的行占用
                    Object.keys(rowOccupancyRef.current).forEach(row => {
                      const rowNum = parseInt(row);
                      if (now - rowOccupancyRef.current[rowNum] > 8000) { // 8秒后释放
                        delete rowOccupancyRef.current[rowNum];
                      }
                    });

                    // 查找可用行
                    let availableRow = -1;
                    for (let i = 0; i < maxRows; i++) {
                      if (!rowOccupancyRef.current[i]) {
                        availableRow = i;
                        break;
                      }
                    }

                    // 如果没有可用行，使用最旧的行
                    if (availableRow === -1) {
                      const oldestRow = Object.keys(rowOccupancyRef.current).reduce((oldest, current) =>
                        rowOccupancyRef.current[parseInt(current)] < rowOccupancyRef.current[parseInt(oldest)] ? current : oldest
                      );
                      availableRow = parseInt(oldestRow);
                    }

                    // 占用行
                    rowOccupancyRef.current[availableRow] = now;

                    // 计算弹幕位置 (每行间距约12%，覆盖更多区域)
                    const top = availableRow * 12 + 8; // 8% 起始位置，让弹幕能经过人物头部

                    setDanmus(prev => [...prev, { id, text, color, duration, top }]);
                    setDanmuText("");

                    // 自动清理弹幕和释放行
                    setTimeout(() => {
                      setDanmus(prev => prev.filter(x => x.id !== id));
                      delete rowOccupancyRef.current[availableRow];
                    }, (duration + 1) * 1000);
                  }}
                >发送</button>
                <div className="danmu-emoji-container">
                  <button
                    className="danmu-emoji-btn"
                    onClick={() => setShowEmojiPicker(!showEmojiPicker)}
                    title="选择表情"
                  >
                    😀
                  </button>
                  {showEmojiPicker && (
                    <EmojiPicker
                      onEmojiSelect={handleEmojiSelect}
                    />
                  )}
                </div>
                <button
                  className="danmu-manage-btn"
                  onClick={() => setShowDanmuManager(true)}
                  title="管理弹幕"
                >
                  📝
                </button>
                <button
                  className="danmu-settings-btn"
                  onClick={() => setShowDanmuSettings(true)}
                  title="弹幕设置"
                >
                  ⚙️
                </button>
                <button
                  className="danmu-filter-btn"
                  onClick={() => setShowSensitiveWordsManager(true)}
                  title="敏感词管理"
                >
                  🛡️
                </button>
              </div>
            </div>
          </div>
          {/* 语音控制区域移除，保留底部彩球与气泡显示，不影响语音识别功能 */}
        </div>
      </div>

      {/* 地板 */}
      <div className="myself-floor"></div>

      {/* 语音按钮——只有管理员能用 */}
      <div className="voice-orb-container">
        <AuthButton
          className={`voice-orb${isRecording ? ' recording' : isProcessing ? ' processing' : ' paused'}`}
          allowRoles={['admin']}
          onClick={(e) => {
            e.stopPropagation();
            if (isRecording) {
              stopRecording();
            } else if (!isProcessing) {
              // 开始新的语音录入前，彻底停止当前播放的语音
              console.log('🛑 点击彩球，彻底停止当前语音播放');
              voiceChatManager.stopSpeaking();
              startRecording();
            }
          }}
          aria-label={isRecording ? '停止录音' : isProcessing ? '处理中' : '开始录音'}
        >
          <img
            className="voice-orb-img"
            src={
              isRecording
                ? '/src/assets/img/speeching.gif'
                : isProcessing
                  ? '/src/assets/img/speaking.jpeg'
                  : '/src/assets/img/speaking.jpeg'
            }
            alt={isRecording ? '录音中' : isProcessing ? '处理中' : '语音待机'}
          />
        </AuthButton>

        {/* 语音识别结果显示在彩球旁边 */}
        {voiceDisplayText && (
          <div className="voice-speech-bubble">
            <div className="voice-speech-content">
              {voiceDisplayText}
            </div>
            <div className="voice-speech-tail"></div>
          </div>
        )}

        {/* 状态信息显示 */}
        {(isRecording || isProcessing || voiceError) && (
          <div className="voice-status-bubble">
            <div className="voice-status-content">
              {isRecording && "🎤 录音中..."}
              {isProcessing && !isRecording && "🔄 处理中..."}
              {voiceError && `❌ 错误: ${voiceError}`}
            </div>
            {(voiceError || (!isRecording && !isProcessing)) && (
              <button
                className="voice-status-clear"
                onClick={clearResult}
                title="清除状态"
              >
                ×
              </button>
            )}
          </div>
        )}
      </div>

      {/* 语音设置按钮 - 单独定位在彩球右边 */}
      <AuthButton
        className="voice-settings-orb-btn"
        allowRoles={['admin']}
        onClick={(e) => {
          e.stopPropagation();
          setShowVoiceSettings(true);
        }}
        aria-label="语音设置"
        title="语音设置"
      >
        🎤
      </AuthButton>

      {/* 对话导出按钮 - 定位在语音设置按钮下方 */}
      <AuthButton
        className="chat-export-orb-btn"
        allowRoles={['admin']}
        onClick={(e) => {
          e.stopPropagation();
          setShowChatExport(true);
        }}
        aria-label="导出对话"
        title="导出对话历史"
      >
        📤
      </AuthButton>

      {/* AI对话UI组件 */}
      <ConversationStatus
        isListening={voiceChatState.isListening}
        isProcessing={voiceChatState.isProcessing}
        isAiThinking={voiceChatState.isAiThinking}
        isAiResponding={voiceChatState.isAiResponding}
        error={voiceChatState.error}
      />

      <AiResponseBubble
        response={voiceChatState.aiResponse}
        isComplete={!voiceChatState.isAiResponding && voiceChatState.aiResponse !== ''}
        isVisible={voiceChatState.aiResponse !== ''}
      />


      {/* 弹幕管理器 */}
      {showDanmuManager && (
        <DanmuManager onClose={() => setShowDanmuManager(false)} />
      )}

      {/* 弹幕设置面板 */}
      {showDanmuSettings && (
        <DanmuSettingsPanel
          settings={danmuSettings}
          onSettingsChange={handleDanmuSettingsChange}
          onClose={() => setShowDanmuSettings(false)}
        />
      )}

      {/* 敏感词管理面板 */}
      {showSensitiveWordsManager && (
        <SensitiveWordsManager
          onClose={() => setShowSensitiveWordsManager(false)}
        />
      )}

      {/* 语音设置面板 */}
      {showVoiceSettings && (
        <VoiceSettingsPanel
          onClose={() => setShowVoiceSettings(false)}
        />
      )}

      {/* 对话导出面板 */}
      {showChatExport && (
        <ChatExport
          onClose={() => setShowChatExport(false)}
        />
      )}

      {/* 换肤弹框 */}
      <SkinChangeModal
        isOpen={showSkinChangeModal}
        onClose={handleCloseSkinModal}
        currentClothingSkin={currentClothingSkin}
        currentPantsSkin={currentPantsSkin}
        currentShoesSkin={currentShoesSkin}
        currentHairSkin={currentHairSkin}
        availableSkins={availableSkins}
        onClothingSkinChange={handleClothingSkinChange}
        onPantsSkinChange={handlePantsSkinChange}
        onShoesSkinChange={handleShoesSkinChange}
        onHairSkinChange={handleHairSkinChange}
        onApplyClothingSkin={handleApplyClothingSkin}
        onApplyPantsSkin={handleApplyPantsSkin}
        onApplyShoesSkin={handleApplyShoesSkin}
        onApplyHairSkin={handleApplyHairSkin}
      />
    </div>
  )
}

export default MySelf; function Avatar({ url, currentAnimation, currentClothingSkin, currentPantsSkin, currentShoesSkin, currentHairSkin }: {
  url: string,
  currentAnimation: string,
  currentClothingSkin: string,
  currentPantsSkin: string,
  currentShoesSkin: string,
  currentHairSkin: string
}) {
  const groupRef = useRef<Group>(null!);
  const mixerRef = useRef<AnimationMixer | null>(null);

  const gltf = useGLTF(url);

  const { actions, names } = useAnimations(gltf.animations ?? [], groupRef);
  const clipNames = useMemo(() => names ?? [], [names]);

  // 保存原始材质的函数
  const saveOriginalMaterials = useCallback(() => {
    if (!gltf.scene) return;

    gltf.scene.traverse((child) => {
      if (child instanceof Mesh && child.material) {
        // 保存原始材质到 userData 中
        if (!child.userData.originalMaterial) {
          child.userData.originalMaterial = child.material.clone();
          console.log('保存原始材质:', child.name);
        }
      }
    });
  }, [gltf.scene]);

  // 换肤功能 - 分离衣服、裤子、鞋子和头发
  const applySkinMaterial = useCallback((clothingSkinId: string, pantsSkinId: string, shoesSkinId: string, hairSkinId: string) => {
    if (!gltf.scene) return;

    // 定义皮肤颜色映射
    const skinColors: { [key: string]: string } = {
      'red': '#FF6B6B',
      'blue': '#4ECDC4',
      'green': '#45B7D1',
      'purple': '#9B59B6',
      'yellow': '#F39C12'
    };

    const clothingColor = skinColors[clothingSkinId];
    const pantsColor = skinColors[pantsSkinId];
    const shoesColor = skinColors[shoesSkinId];
    const hairColor = skinColors[hairSkinId];

    // 遍历模型的所有网格，分别处理衣服、裤子、鞋子和头发
    gltf.scene.traverse((child) => {
      if (child instanceof Mesh) {
        const meshName = child.name.toLowerCase();

        // 处理衣服部分
        const isClothing = meshName.includes('shirt') ||
          meshName.includes('dress') ||
          meshName.includes('top') ||
          meshName.includes('jacket') ||
          meshName.includes('coat') ||
          meshName.includes('sweater');

        // 处理裤子部分
        const isPants = meshName.includes('pants') ||
          meshName.includes('trousers') ||
          meshName.includes('jeans') ||
          meshName.includes('shorts') ||
          meshName.includes('legs') ||
          meshName.includes('bottom');

        // 处理鞋子部分
        const isShoes = meshName.includes('shoe') ||
          meshName.includes('boot') ||
          meshName.includes('sneaker') ||
          meshName.includes('footwear') ||
          meshName.includes('foot') ||
          meshName.includes('feet');

        // 处理头发部分
        const isHair = meshName.includes('hair') ||
          meshName.includes('head_hair') ||
          meshName.includes('scalp') ||
          meshName.includes('ponytail') ||
          meshName.includes('bangs') ||
          meshName.includes('braid');

        // 处理衣服换肤
        if (isClothing) {
          if (clothingSkinId === 'original') {
            // 恢复原始材质 - 重新加载模型来获取原始材质
            console.log('恢复衣服原始材质:', child.name);
            // 这里我们通过重新克隆原始材质来恢复
            if (child.userData.originalMaterial) {
              child.material = child.userData.originalMaterial.clone();
              child.material.needsUpdate = true;
            }
          } else if (clothingColor) {
            console.log('应用衣服新材质:', child.name);
            const newMaterial = new MeshStandardMaterial({
              color: clothingColor,
              metalness: 0.1,
              roughness: 0.8
            });
            child.material = newMaterial;
            child.material.needsUpdate = true;
          }
        }

        // 处理裤子换肤
        if (isPants) {
          if (pantsSkinId === 'original') {
            console.log('恢复裤子原始材质:', child.name);
            if (child.userData.originalMaterial) {
              child.material = child.userData.originalMaterial.clone();
              child.material.needsUpdate = true;
            }
          } else if (pantsColor) {
            console.log('应用裤子新材质:', child.name);
            const newMaterial = new MeshStandardMaterial({
              color: pantsColor,
              metalness: 0.1,
              roughness: 0.8
            });
            child.material = newMaterial;
            child.material.needsUpdate = true;
          }
        }

        // 处理鞋子换肤
        if (isShoes) {
          if (shoesSkinId === 'original') {
            console.log('恢复鞋子原始材质:', child.name);
            if (child.userData.originalMaterial) {
              child.material = child.userData.originalMaterial.clone();
              child.material.needsUpdate = true;
            }
          } else if (shoesColor) {
            console.log('应用鞋子新材质:', child.name);
            const newMaterial = new MeshStandardMaterial({
              color: shoesColor,
              metalness: 0.2,
              roughness: 0.7
            });
            child.material = newMaterial;
            child.material.needsUpdate = true;
          }
        }

        // 处理头发换肤
        if (isHair) {
          if (hairSkinId === 'original') {
            console.log('恢复头发原始材质:', child.name);
            if (child.userData.originalMaterial) {
              child.material = child.userData.originalMaterial.clone();
              child.material.needsUpdate = true;
            }
          } else if (hairColor) {
            console.log('应用头发新材质:', child.name);
            const newMaterial = new MeshStandardMaterial({
              color: hairColor,
              metalness: 0.0,
              roughness: 0.9
            });
            child.material = newMaterial;
            child.material.needsUpdate = true;
          }
        }
      }
    });
  }, [gltf.scene]);

  // 使用位置更新Hook
  useCharacterPositionUpdater({
    characterPosition: new Vector3(0, 1.5, 0), // 固定位置
    enabled: true
  });

  // 模型加载完成后保存原始材质
  useEffect(() => {
    if (gltf.scene) {
      saveOriginalMaterials();
    }
  }, [gltf.scene, saveOriginalMaterials]);

  console.log('=== Avatar 组件调试信息 ===');
  console.log('模型URL:', url);
  console.log('当前动画:', currentAnimation);
  console.log('当前衣服皮肤:', currentClothingSkin);
  console.log('当前裤子皮肤:', currentPantsSkin);
  console.log('当前鞋子皮肤:', currentShoesSkin);
  console.log('当前头发皮肤:', currentHairSkin);
  console.log('GLTF 对象:', gltf);
  console.log('GLTF 场景:', gltf.scene);
  console.log('GLTF 场景子对象数量:', gltf.scene?.children?.length || 0);
  console.log('GLTF 场景子对象:', gltf.scene?.children);
  console.log('模型是否加载完成:', gltf.scene ? '是' : '否');
  console.log('可用动画:', clipNames);
  console.log('动画数量:', clipNames.length);
  console.log('========================');

  // 确保模型在加载后立即定位到正确位置
  useEffect(() => {
    if (groupRef.current) {
      // 强制设置模型位置和旋转
      groupRef.current.position.set(0, 0, 0);
      groupRef.current.rotation.set(0, 0, 0);
      groupRef.current.scale.set(0.9, 0.9, 0.9);

      // 禁用模型的交互
      groupRef.current.traverse((child) => {
        if (child instanceof Mesh) {
          child.userData.interactive = false;
        }
      });
    }
  }, [gltf.scene]);

  // 当皮肤改变时应用新材质
  useEffect(() => {
    if (gltf.scene) {
      applySkinMaterial(currentClothingSkin, currentPantsSkin, currentShoesSkin, currentHairSkin);
    }
  }, [currentClothingSkin, currentPantsSkin, currentShoesSkin, currentHairSkin, gltf.scene, applySkinMaterial]);

  // 加载本地 FBX 动画
  useEffect(() => {
    // 检查是否是FBX动画类型
    const isFbxAnimation = currentAnimation === "clap" || currentAnimation === "angry" || currentAnimation === "flair" || currentAnimation === "hiphop" || currentAnimation === "rumba" || currentAnimation === "greeting" || currentAnimation === "idle";

    if (isFbxAnimation) {
      // 根据动画类型选择对应的FBX文件
      let fbxFile = "";
      switch (currentAnimation) {
        case "idle":
          fbxFile = "/animations/Standing W_Briefcase Idle.fbx";
          break;
        case "clap":
          fbxFile = "/animations/Standing Clap.fbx";
          break;
        case "angry":
          fbxFile = "/animations/Angry.fbx";
          break;
        case "flair":
          fbxFile = "/animations/Flair.fbx";
          break;
        case "hiphop":
          fbxFile = "/animations/Hip Hop Dancing.fbx";
          break;
        case "rumba":
          fbxFile = "/animations/Rumba Dancing.fbx";
          break;
        case "greeting":
          fbxFile = "/animations/Standing Greeting.fbx";
          break;
        default:
          return;
      }

      console.log(`开始加载 FBX 动画: ${fbxFile}`);
      const loader = new FBXLoader();
      loader.load(fbxFile, (fbx: Object3D) => {
        console.log('FBX 加载成功:', fbx);
        if (groupRef.current && fbx.animations && fbx.animations.length > 0) {
          console.log('找到动画片段:', fbx.animations.length);
          // 创建动画混合器
          mixerRef.current = new AnimationMixer(groupRef.current);

          // 获取第一个动画片段
          const clip = fbx.animations[0];
          const action = mixerRef.current.clipAction(clip);

          // 播放动画
          action.reset();
          action.setLoop(LoopRepeat, Infinity);
          action.fadeIn(0.3).play();
          console.log(`${currentAnimation} 动画开始播放`);
        } else {
          console.log('没有找到动画片段或 groupRef 为空');
        }
      }, undefined, (error: unknown) => {
        console.error('加载 FBX 动画失败:', error);
      });
    } else {
      // 如果不是FBX动画，清除 FBX 动画
      if (mixerRef.current) {
        mixerRef.current.stopAllAction();
        mixerRef.current = null;
      }
    }
  }, [currentAnimation]);

  // 更新动画混合器
  useFrame((_, delta) => {
    if (mixerRef.current) {
      mixerRef.current.update(delta);
    }
  });

  // 播放模型自带动画
  useEffect(() => {
    // 检查是否是FBX动画类型，如果是则跳过模型动画
    const isFbxAnimation = currentAnimation === "clap" || currentAnimation === "angry" || currentAnimation === "flair" || currentAnimation === "hiphop" || currentAnimation === "rumba" || currentAnimation === "greeting" || currentAnimation === "idle";
    if (isFbxAnimation || mixerRef.current) return; // 如果有FBX动画就不使用模型动画

    if (!actions || clipNames.length === 0) return;
    console.log('可用动画列表:', clipNames);

    // 停止所有当前动画
    Object.values(actions).forEach(action => {
      if (action && action.isRunning()) {
        action.fadeOut(0.3);
      }
    });

    // 根据选择播放对应动画
    let selectedAction = null;
    if (currentAnimation === "walk") {
      selectedAction = clipNames.find(n => n.toLowerCase().includes("walk"));
    } else if (currentAnimation === "dance") {
      selectedAction = clipNames.find(n => n.toLowerCase().includes("dance"));
    }

    const actionName = selectedAction || clipNames[0];
    const action = actions[actionName];
    if (action) {
      action.reset();
      action.setLoop(LoopRepeat, Infinity);
      action.fadeIn(0.3).play();
      console.log(`播放模型动画: ${actionName}`);
    }
  }, [actions, clipNames, currentAnimation]);

  // 确保模型始终保持在固定位置，只在偏离时重置
  useFrame(() => {
    if (groupRef.current) {
      const pos = groupRef.current.position;
      const rot = groupRef.current.rotation;

      // 强制保持固定位置，任何偏离都立即重置
      if (Math.abs(pos.x) > 0.001 || Math.abs(pos.y) > 0.001 || Math.abs(pos.z) > 0.001) {
        groupRef.current.position.set(0, 0, 0);
      }

      if (Math.abs(rot.x) > 0.001 || Math.abs(rot.y) > 0.001 || Math.abs(rot.z) > 0.001) {
        groupRef.current.rotation.set(0, 0, 0);
      }

      // 确保缩放保持固定
      const scale = groupRef.current.scale;
      if (Math.abs(scale.x - 0.9) > 0.001 || Math.abs(scale.y - 0.9) > 0.001 || Math.abs(scale.z - 0.9) > 0.001) {
        groupRef.current.scale.set(0.9, 0.9, 0.9);
      }

      // 位置更新由useCharacterPositionUpdater Hook处理
    }
  });


  // 如果模型没有加载，显示一个简单的3D人物占位符
  if (!gltf.scene) {
    console.log('模型未加载，显示简单3D人物占位符');
    return (
      <group ref={groupRef}>
        {/* 头部 */}
        <mesh position={[0, 1.7, 0]}>
          <sphereGeometry args={[0.3, 16, 16]} />
          <meshStandardMaterial color="#ffdbac" />
        </mesh>

        {/* 身体 */}
        <mesh position={[0, 1.2, 0]}>
          <boxGeometry args={[0.6, 0.8, 0.3]} />
          <meshStandardMaterial color="#4a90e2" />
        </mesh>

        {/* 手臂 */}
        <mesh position={[-0.4, 1.2, 0]}>
          <boxGeometry args={[0.2, 0.6, 0.2]} />
          <meshStandardMaterial color="#ffdbac" />
        </mesh>
        <mesh position={[0.4, 1.2, 0]}>
          <boxGeometry args={[0.2, 0.6, 0.2]} />
          <meshStandardMaterial color="#ffdbac" />
        </mesh>

        {/* 腿部 */}
        <mesh position={[-0.15, 0.4, 0]}>
          <boxGeometry args={[0.2, 0.8, 0.2]} />
          <meshStandardMaterial color="#2c3e50" />
        </mesh>
        <mesh position={[0.15, 0.4, 0]}>
          <boxGeometry args={[0.2, 0.8, 0.2]} />
          <meshStandardMaterial color="#2c3e50" />
        </mesh>

        {/* 标签文本 */}
        <mesh position={[0, 2.5, 0]}>
          <planeGeometry args={[1, 0.3]} />
          <meshBasicMaterial color="orange" transparent opacity={0.8} />
        </mesh>
      </group>
    );
  }

  console.log('渲染模型:', gltf.scene);
  return (
    <group ref={groupRef}>
      <primitive object={gltf.scene} scale={0.9} />
    </group>
  );
}

